#include "rtcp_handler.h"

#include <chrono>
#include <cmath>
#include <cstdlib>
#include <memory>

#include "xcutil.h"
#include "xm_log.h"
#include "xrtcp_util.h"
#include "xsdp.h"

#include "xm_app_config.h"
#include "xrtc_endpoint.h"


class rtcp_handler {
public:
    char id[128] = {0,};
    rtc_endpoint_t rtc;
    uint32_t ssrc;
    uint32_t placeholder_ssrc;
    rtc_endpoint_callback_link_t callback_link;

    uint64_t last_sr_receive_time_local_clock = 0;
    uint32_t last_receive_sr_ntp_middle_32 = 0; // a.k.a. LSR
    uint32_t delay_since_last_report = 0; // a.k.a DLSR
    uint8_t lost_fraction = 0;
    uint32_t lost_cumulative = 0;

    uint16_t max_seq = 0;
    uint32_t base_seq = 0;
    uint16_t cycles = 0;
    uint32_t extended_seq = 0;
    uint32_t last_rtp_timestamp = 0;
    uint32_t received_rtp_packets = 0;
    int32_t transit_duration = 0;
    bool transit_duration_set = false;
    double jitter = 0.0;

    uint32_t expected_prior = 0;
    uint32_t received_prior = 0;

    rtcp_parser_t rtcp_parser;

    static const uint32_t last_lost_rates_length = 3;
    uint32_t last_lost_rates[last_lost_rates_length];
    uint64_t last_lost_rate_next_index = 0;
    uint32_t last_lost_rate_avg = 0;
};


// callbacks required by rtc_endpoint
static bool rtcp_handler_on_endpoint_data(rtc_endpoint_t rtc, void * context, int stream_type, rtc_codec_id_t codec, rtc_codec_id_t fec_codec, int data_type, int is_rtcp, int is_rtx, unsigned char * buf, int len);
// private functions
static void _rtcp_handler_handle_rtcp_data(rtcp_handler* handler, rtc_endpoint_t rtc, unsigned char* buf, int len);

static void _rtcp_handler_handle_sender_report(rtcp_handler* handler, const RTCPPacketSR* sr);

static void _rtcp_handler_handle_rtp_data(rtcp_handler_t o, rtc_endpoint_t rtc, int codec, unsigned char* buf, int len);

static void _rtcp_handler_calculate_receiver_report(rtcp_handler_t o, uint64_t now_epoch_ms);

rtc_endpoint_callbacks rtcp_handler_callbacks = {
        .context = nullptr,
        .on_destroy = nullptr,
        .on_stream_data = rtcp_handler_on_endpoint_data,
        .on_event = nullptr
};

static bool rtcp_handler_on_endpoint_data(rtc_endpoint_t rtc, void * context, int stream_type, rtc_codec_id_t codec, rtc_codec_id_t fec_codec, int data_type, int is_rtcp, int is_rtx, unsigned char * buf, int len) {
    rtcp_handler* self = static_cast<rtcp_handler*>(context);
    if (data_type != RTC_RECV_CLEAR) {
        return false;
    }
//	dbgi("rtcp_handler_on_endpoint_data send data_type is:%d,the len is:%d the stream_type is:%d is rtcp %d is_rtx is:%d",data_type,len,stream_type,is_rtcp,is_rtx);

    if (is_rtcp) {
        _rtcp_handler_handle_rtcp_data(self, rtc, buf, len);
    } else if (!is_rtx) {
        _rtcp_handler_handle_rtp_data(self, rtc, codec, buf, len);
    }

    return false;
}

static void _rtcp_handler_handle_rtcp_data(rtcp_handler* handler, rtc_endpoint_t rtc, unsigned char* buf, int len) {
    int pkttype = rtcp_parse_first(handler->rtcp_parser, buf, len);

    const RTCPPacket * body = rtcp_get_body(handler->rtcp_parser);

    int report_nb = 0;
    while( pkttype != kInvalid){
        switch (pkttype) {
            case kSr:
                _rtcp_handler_handle_sender_report(handler, &body->SR);
                break;
            case kRr:
                if (body->RR.NumberOfReportBlocks > 0) {
                    report_nb = body->RR.NumberOfReportBlocks;
                    pkttype = rtcp_parse_next_item(handler->rtcp_parser);
                } else {
                    pkttype = rtcp_parse_next_packet(handler->rtcp_parser);
                }
                continue;
            case kReportBlockItem: {
                uint32_t media_ssrc = body->ReportBlockItem.SSRC;
                uint32_t hseq = body->ReportBlockItem.ExtendedHighestSequenceNumber;
                uint32_t lsr = body->ReportBlockItem.LastSR;
                uint32_t dslr = body->ReportBlockItem.DelayLastSR;
                // uint8_t lost_frac = body->ReportBlockItem.FractionLost;
                // uint32_t lost_cum = body->ReportBlockItem.CumulativeNumOfPacketsLost;
                // uint32_t jitter = body->ReportBlockItem.Jitter;
                int64_t rcv_ts = get_timestamp_ms();
                uint32_t now = ms_to_ntp_mid32(rcv_ts);
                uint32_t rtt_ntp_mid32 = 0;

                if (lsr != 0 && app_config_get()->log_if_rtt_ge) {
                    if (now >= lsr) {
                        rtt_ntp_mid32 = now - lsr;
                    } else {
                        // handling wrapped now as follows:
                        rtt_ntp_mid32 = 0xFFFFFFFFu - lsr + now + 1;
                    }
                    if (rtt_ntp_mid32 > dslr) {
                        rtt_ntp_mid32 -= dslr;
                    } else {
                        rtt_ntp_mid32 = 0;
                    }

                    uint64_t rtt_ms = (rtt_ntp_mid32 * 1000) >> 16;
                    if(rtt_ms >= app_config_get()->log_if_rtt_ge){
                        dbgi("rtc = %s rtt too large, rtcp ssrc=%X, hseq=%u, %lu millis >= %lu, lsr=%u",
                             rtc_endpoint_get_id(rtc), media_ssrc, hseq, rtt_ms, app_config_get()->log_if_rtt_ge, lsr);
                    }
                }

                report_nb -= 1;
                if (report_nb > 0) {
                    pkttype = rtcp_parse_next_item(handler->rtcp_parser);
                } else {
                    pkttype = rtcp_parse_next_packet(handler->rtcp_parser);
                }

                continue;
            }
        }
        pkttype = rtcp_parse_next_packet(handler->rtcp_parser);
    }
}

static void _rtcp_handler_handle_sender_report(rtcp_handler* handler, const RTCPPacketSR* sr) {
    if (sr->SenderSSRC != handler->ssrc && sr->SenderSSRC != handler->placeholder_ssrc) {
        return;
    }
    handler->last_sr_receive_time_local_clock = get_timestamp_ms();
    handler->last_receive_sr_ntp_middle_32 = (sr->NTPMostSignificant << 16) | (sr->NTPLeastSignificant >> 16);
}

static void _rtcp_handler_handle_rtp_data(rtcp_handler_t handler, rtc_endpoint_t rtc, int codec, unsigned char* buf, int len) {
    rtcp_handler* self = static_cast<rtcp_handler*>(handler);
    uint32_t ssrc = be_get_u32(buf+8);
    uint16_t seq = be_get_u16(buf+2);
    uint32_t timestamp = be_get_u32(buf+4);
    uint32_t clock_rate = 90;
    switch (codec) {
        case rtc_codec_id_opus:
            clock_rate = 48;
            break;
        case rtc_codec_id_vp8:
            clock_rate = 90;
            break;
        case rtc_codec_id_h264:
            clock_rate = 90;
            break;
        case rtc_codec_id_ulpfec:
            clock_rate = 90;
            break;
        default:
            return;
    }

    if (self->ssrc != ssrc && self->placeholder_ssrc != ssrc) {
        return;
    }
    // todo: add receive time, do not call now too often

    if (!self->received_rtp_packets) {
        self->max_seq = seq;
        self->base_seq = seq;
    } else if (seq < self->max_seq) {
        uint16_t d = seq - self->max_seq;
        if (d < 3000) {
            ++self->cycles;
            self->max_seq = seq;
        }
    } else {
        self->max_seq = seq;
    }
    ++self->received_rtp_packets;
    self->extended_seq = (self->cycles << 16) | self->max_seq;
    auto now_epoch_ms = get_timestamp_ms();
    int transit_duration = now_epoch_ms * clock_rate - timestamp;
    if (self->transit_duration_set) {
        int delta = std::abs(transit_duration - self->transit_duration);
        self->jitter += (static_cast<double>(delta) - self->jitter) / 16;
    }
    self->transit_duration = transit_duration;
    self->transit_duration_set = true;
}

static void _rtcp_handler_calculate_receiver_report(rtcp_handler_t handler, uint64_t now_epoch_ms) {
    rtcp_handler* self = static_cast<rtcp_handler*>(handler);

    self->delay_since_last_report = self->last_sr_receive_time_local_clock ? static_cast<uint32_t>((now_epoch_ms - self->last_sr_receive_time_local_clock) * 65536 / 1000) : 0;
    uint32_t expected = self->extended_seq - self->base_seq + 1;
    self->lost_cumulative = expected - self->received_rtp_packets;
    if (self->lost_cumulative > 0x7FFFFFu) {
        self->lost_cumulative = 0x800000u;
    }
    uint32_t expected_interval = expected - self->expected_prior;
    uint32_t received_interval = self->received_rtp_packets - self->received_prior;
    self->expected_prior = expected;
    self->received_prior = self->received_rtp_packets;
    uint32_t lost_interval = expected_interval - received_interval;
    self->lost_fraction = 0;
    if (expected_interval != 0 && lost_interval > 0) {
        self->lost_fraction = (lost_interval << 8) / expected_interval;
    }
}

rtcp_handler_t rtcp_handler_new(rtc_endpoint_t rtc, uint32_t ssrc, uint32_t placeholder_ssrc) {
    const char* rtc_id = rtc_endpoint_get_id(rtc);
    auto g = new rtcp_handler();
    snprintf(g->id, sizeof(g->id) - 1, "%s:0x%x", rtc_id, ssrc);
    g->rtc = rtc;
    g->ssrc = ssrc;
    g->placeholder_ssrc = placeholder_ssrc;
    g->rtcp_parser = rtcp_parser_create();
    dbgv("|%s| new rtcp handler", g->id);
    rtc_endpoint_register_callback(rtc, g, &rtcp_handler_callbacks);
    return g;
}

void rtcp_handler_destroy(rtcp_handler_t handler) {
    rtcp_handler* self = static_cast<rtcp_handler*>(handler);
    dbgv("|%s| destroy rtcp handler", self->id);
    if (self->callback_link) {
        rtc_endpoint_unregister_callback(self->rtc, self->callback_link);
        self->callback_link = nullptr;
    }
    if (self->rtcp_parser) {
        rtcp_parser_delete(self->rtcp_parser);
        self->rtcp_parser = nullptr;
    }

    delete self;
}

void rtcp_handler_get_report(rtcp_handler_t handler, rtcp_report_t& report) {
    rtcp_handler* self = static_cast<rtcp_handler*>(handler);
    auto now_epoch_ms = get_timestamp_ms();
    _rtcp_handler_calculate_receiver_report(self, now_epoch_ms);
    report.lost_frac = self->lost_fraction;
    report.lost_cumulative = self->lost_cumulative;
    report.extended_highest_seq = self->extended_seq;
    report.inter_arrival_jitter = static_cast<uint32_t>(std::round(self->jitter));
    report.lsr = self->last_receive_sr_ntp_middle_32;
    report.dlsr = self->delay_since_last_report;


    // 计算最近几次的平均值
    uint32_t lost_rate = self->lost_fraction;
    lost_rate = (lost_rate * 100) >> 8;
    self->last_lost_rates[self->last_lost_rate_next_index % rtcp_handler::last_lost_rates_length] = lost_rate;
    self->last_lost_rate_next_index = self->last_lost_rate_next_index + 1;

    uint32_t startIndex = 0;
    if(self->last_lost_rate_next_index <= rtcp_handler::last_lost_rates_length){
        startIndex = 0;
    }else{
        startIndex = self->last_lost_rate_next_index - rtcp_handler::last_lost_rates_length;
    }

    uint32_t sum = 0;
    for(uint32_t i = startIndex; i < self->last_lost_rate_next_index; i++){
        sum += self->last_lost_rates[i % rtcp_handler::last_lost_rates_length];
    }
    uint32_t count = self->last_lost_rate_next_index - startIndex;
    if(count > 0){
        self->last_lost_rate_avg = sum / count;
    }
    // 计算最近几次的平均值 END

    report.last_lost_rate_avg = self->last_lost_rate_avg;
}

